package cn.slipi.admin.service.impl;

import cn.slipi.admin.common.contants.ServiceConstants;
import cn.slipi.admin.common.dto.PageDTO;
import cn.slipi.admin.common.exception.base.BizException;
import cn.slipi.admin.common.utils.StrUtils;
import cn.slipi.admin.common.utils.cache.redis.RedisClient;
import cn.slipi.admin.common.utils.dozer.impl.ConvertBean;
import cn.slipi.admin.dao.TSysPermissionMapper;
import cn.slipi.admin.entity.*;
import cn.slipi.admin.service.*;
import cn.slipi.admin.service.dto.in.m.*;
import cn.slipi.admin.service.dto.out.PermissionDTO;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * <p>
 * 系统权限表 服务实现类
 * </p>
 *
 * @author lee
 * @since 2020-10-09
 */
@Service
public class TSysPermissionServiceImpl extends ServiceImpl<TSysPermissionMapper, TSysPermission> implements TSysPermissionService {
    @Autowired
    private ConvertBean convertBean;

    @Autowired
    private RedisClient redisClient;

    @Autowired
    private TSysRoleService sysRoleService;

    @Autowired
    private TSysMenuService sysMenuService;

    @Autowired
    private TSysRoleMenuService sysRoleMenuService;

    @Autowired
    private TSysRoleAdminService sysRoleAdminService;

    @Autowired
    private TSysPermissionModuleService sysPermissionModuleService;

    @Autowired
    private TSysRolePermissionService sysRolePermissionService;


    @Override
    @Transactional(rollbackFor = BizException.class)
    public Boolean saveRolePermission(Integer rid, List<Integer> permissionIds) {
        //拷贝备用
        List<Integer> needAddPermissionIds = new ArrayList<>(permissionIds);
        //获取角色原拥有的权限
        List<TSysRolePermission> curRolePermissionList = this.getRolePermissionByRoleId(rid);
        List<Integer> curPermissionIds = curRolePermissionList.stream().map(TSysRolePermission::getPermissionId).collect(Collectors.toList());
        //拷贝备用
        List<Integer> needDelPermissionIds = new ArrayList<>(curPermissionIds);
        //求差集新权限有老权限没有的ids（需要添加）
        needAddPermissionIds.removeAll(curPermissionIds);
        if (needAddPermissionIds.size() > 0) {
            needAddPermissionIds.forEach(needAddPermissionId -> {
                TSysRolePermission rolePermission = new TSysRolePermission();
                rolePermission.setRoleId(rid);
                rolePermission.setPermissionId(needAddPermissionId);
                this.sysRolePermissionService.getBaseMapper().insert(rolePermission);
            });
        }
        //(需要删除)
        needDelPermissionIds.removeAll(permissionIds);
        if (needDelPermissionIds.size() > 0) {
            this.deleteRolePermissionByPermissionId(needDelPermissionIds);
        }
        return true;
    }

    @Override
    @Transactional(rollbackFor = BizException.class)
    public Boolean updateRole(Integer rid, RoleSaveDTO roleSaveDTO) {
        TSysRole role = this.getRoleByRoleId(rid);

        if (null == role) {
            throw new BizException(10000, "role.fund.not");
        }

        if (!role.getName().equals(roleSaveDTO.getName())) {
            List<TSysRole> roles = this.getRoleByName(roleSaveDTO.getName());
            if (roles.size() > 0) {
                throw new BizException(10000, "role.name.fund");
            }
        }

        this.convertBean.convertNotNull(roleSaveDTO, role, false, true);

        this.sysRoleService.getBaseMapper().updateById(role);
        return true;
    }

    @Override
    @Transactional(rollbackFor = BizException.class)
    public Integer addRole(RoleSaveDTO roleSaveDTO) {
        TSysRole role = new TSysRole();
        this.convertBean.convert(roleSaveDTO, role);

        List<TSysRole> roles = this.getRoleByName(role.getName());
        if (roles.size() > 0) {
            throw new BizException(10000, "role.name.fund");
        }
        this.sysRoleService.getBaseMapper().insert(role);
        return role.getId();
    }

    @Override
    @Transactional(rollbackFor = BizException.class)
    public Boolean updatePermissionModule(String pid, Integer mid) {
        /**
         * update Permission p set p.moduleId = :mid where p.id in(:pids) and p.status = 1
         */
        QueryWrapper<TSysPermission> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("ID", Long.valueOf(pid));
        queryWrapper.eq("STATUS", 1);
        TSysPermission sysPermission = this.baseMapper.selectOne(queryWrapper);
        sysPermission.setModuleId(mid);
        this.baseMapper.updateById(sysPermission);
        return true;
    }

    @Override
    @Transactional(rollbackFor = BizException.class)
    public Boolean updatePermission(Integer pid, PermissionSaveDTO permissionSaveDTO) {
        TSysPermission permission = this.getPermissionByPermissionId(pid);
        if (null == permission) {
            throw new BizException(10000, "permission.fund.not");
        }
        if (!permission.getCode().equals(permissionSaveDTO.getCode())) {
            TSysPermission ePermission = this.getPermissionByCode(permissionSaveDTO.getCode());
            if (ePermission != null) {
                throw new BizException(10000, "permission.code.fund");
            }
        }
        this.convertBean.convertNotNull(permissionSaveDTO, permission, false, true);
        this.baseMapper.updateById(permission);
        //删除缓存
        this.redisClient.deleteByKey(ServiceConstants.AUTH_PERMISSION);
        return true;
    }

    @Override
    @Transactional(rollbackFor = BizException.class)
    public Integer addPermission(PermissionSaveDTO permissionSaveDTO) {
        TSysPermission permission = this.getPermissionByCode(permissionSaveDTO.getCode());
        if (permission != null) {
            throw new BizException(10000, "permission.code.fund");
        }
        permission = this.convertBean.convert(permissionSaveDTO, TSysPermission.class);
        this.baseMapper.insert(permission);
        //删除缓存
        this.redisClient.deleteByKey(ServiceConstants.AUTH_PERMISSION);
        return permission.getId();
    }

    @Override
    @Transactional(rollbackFor = BizException.class)
    public IPage<TSysRole> getRoleList(RoleQueryDTO dto) {
        IPage<TSysRole> page = new Page<>(dto.getPageNo(), dto.getPageSize());
        QueryWrapper<TSysRole> queryWrapper = new QueryWrapper<>();
        if (StrUtils.isNotBlank(dto.getName())) {
            queryWrapper.like("NAME", dto.getName());
        }
        queryWrapper.eq("STATUS", 1);
        return this.sysRoleService.getBaseMapper().selectPage(page, queryWrapper);
    }

    @Override
    @Transactional(rollbackFor = BizException.class)
    public Integer addModule(ModuleSaveDTO moduleSaveDTO) {
        TSysPermissionModule permissionModule = new TSysPermissionModule();
        this.convertBean.convert(moduleSaveDTO, permissionModule);
        this.sysPermissionModuleService.getBaseMapper().insert(permissionModule);
        return permissionModule.getId();
    }

    @Override
    @Transactional(rollbackFor = BizException.class)
    public Boolean updateModule(Integer mid, ModuleSaveDTO moduleSaveDTO) {
        TSysPermissionModule permissionModule = this.getPermissionModuleById(mid);
        if (null == permissionModule) {
            throw new BizException(10000, "permission.module.fund.not");
        }
        if (!permissionModule.getName().equals(moduleSaveDTO.getName())) {
            List<TSysPermissionModule> permissionModuleList = this.getPermissionModuleByName(moduleSaveDTO.getName());
            if (permissionModuleList.size() > 0) {
                throw new BizException(10000, "role.name.fund");
            }
        }
        this.convertBean.convertNotNull(moduleSaveDTO, permissionModule, false, true);
        this.sysPermissionModuleService.getBaseMapper().updateById(permissionModule);
        return true;
    }

    @Override
    @Transactional(rollbackFor = BizException.class)
    public Boolean deleteModule(Integer mid) {
        TSysPermissionModule permissionModule = this.getPermissionModuleById(mid);
        if (null == permissionModule) {
            throw new BizException(10000, "permission.module.fund.not");
        }
        //判断模块下是否有权限，若有权限提示不允许删除
        List<TSysPermission> permissionList = this.getPermissionByModuleId(mid);
        if (permissionList.size() > 0) {
            throw new BizException(10000, "module.permission.exists.no.del");
        }
        this.sysPermissionModuleService.getBaseMapper().deleteById(permissionModule);
        return true;
    }


    @Override
    @Transactional(rollbackFor = BizException.class)
    public List<TSysMenu> getMenuByAdminId(Integer adminId) {
        List<TSysRole> roleList = getRoleByAdminId(adminId);
        List<TSysMenu> menuList = new ArrayList<>();
        if (roleList.size() > 0) {
            List<Integer> roleIds = roleList.stream().map(TSysRole::getId).collect(Collectors.toList());
            menuList = getMenuByRoleIds(roleIds);
        }
        return menuList;
    }

    @Override
    @Transactional(rollbackFor = BizException.class)
    public List<TSysMenu> getMenuByRoleIds(List<Integer> roleIds) {
        List<TSysMenu> menuList = new ArrayList<>();
        List<TSysRoleMenu> roleMenuList = this.sysRoleMenuService.getRoleMenuByRoleIds(roleIds);
        if (roleMenuList.size() > 0) {
            List<Integer> menuIds = roleMenuList.stream().map(TSysRoleMenu::getMenuId).collect(Collectors.toList());
            menuList = this.sysMenuService.getMenuByIds(menuIds);
        }
        return menuList;
    }

    @Override
    @Transactional(rollbackFor = BizException.class)
    public List<PermissionDTO> getPermissionByAdminId(Integer adminId) {
        List<TSysRole> roleList = getRoleByAdminId(adminId);
        List<Integer> roleIds = roleList.stream().map(TSysRole::getId).collect(Collectors.toList());
        return getPermissionByRoleIds(roleIds);
    }

    @Override
    @Transactional(rollbackFor = BizException.class)
    public List<TSysRole> getRoleByAdminId(Integer adminId) {
        List<TSysRole> roleList = new ArrayList<>();
        List<TSysRoleAdmin> roleAdminList = this.sysRoleAdminService.getRoleAdminByAdminId(adminId);
        if (roleAdminList.size() > 0) {
            List<Integer> roleIds = roleAdminList.stream().map(TSysRoleAdmin::getRoleId).collect(Collectors.toList());
            roleList = this.sysRoleService.getRoleByRoleIds(roleIds);
        }
        return roleList;
    }

    @Override
    @Transactional(rollbackFor = BizException.class)
    public List<PermissionDTO> getPermissionByRoleIds(List<Integer> roleIds) {
        List<PermissionDTO> permissionList = new ArrayList<>();
        if (roleIds.size() > 0) {
            List<TSysRolePermission> rolePermissionList = this.sysRolePermissionService.getRolePermissionByRoleIds(roleIds);
            permissionList = getPermissionListByRolePermissionList(rolePermissionList);
        }
        return permissionList;
    }

    @Override
    @Transactional(rollbackFor = BizException.class)
    public List<TSysPermission> getPermissionByPermissionIds(List<Integer> permissionIds) {
        QueryWrapper<TSysPermission> queryWrapper = new QueryWrapper<>();
        queryWrapper.in("ID", permissionIds);
        queryWrapper.eq("STATUS", 1);
        return this.baseMapper.selectList(queryWrapper);
    }

    @Override
    @Transactional(rollbackFor = BizException.class)
    public List<TSysPermissionModule> getPermissionModuleDropList() {
        /**
         * select pm from PermissionModule pm where  pm.status = 1
         */
        QueryWrapper<TSysPermissionModule> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("STATUS", 1);
        return this.sysPermissionModuleService.getBaseMapper().selectList(queryWrapper);
    }

    @Override
    @Transactional(rollbackFor = BizException.class)
    public List<PermissionDTO> getPermissionAll() {
        QueryWrapper<TSysPermission> queryWrapper = new QueryWrapper<>();
        List<TSysPermission> permissionList = this.baseMapper.selectList(queryWrapper);
        return this.dtoGet(permissionList);
    }

    @Override
    @Transactional(rollbackFor = BizException.class)
    public List<PermissionDTO> getPermissionByRoleId(Integer roleId) {
        List<TSysRolePermission> rolePermissionList = this.getRolePermissionByRoleId(roleId);
        return this.getPermissionListByRolePermissionList(rolePermissionList);
    }

    @Override
    @Transactional(rollbackFor = BizException.class)
    public PageDTO<PermissionDTO> getPermissionList(PermissionQueryDTO dto) {
        IPage<TSysPermission> page = new Page<>(dto.getPageNo(), dto.getPageSize());
        QueryWrapper<TSysPermission> queryWrapper = new QueryWrapper<>();
        if (StrUtils.isNotBlank(dto.getName())) {
            queryWrapper.like("NAME", dto.getName());
        }
        if (StrUtils.isNotBlank(dto.getCode())) {
            queryWrapper.like("CODE", dto.getCode());
        }
        if (StrUtils.isNotBlank(dto.getAction())) {
            queryWrapper.like("ACTION", dto.getAction());
        }
        if (null != dto.getModuleId()) {
            queryWrapper.eq("MODULE_ID", dto.getModuleId());
        }

        queryWrapper.eq("STATUS", 1);

        page = this.baseMapper.selectPage(page, queryWrapper);

        List<PermissionDTO> permissionDTOList = this.dtoGet(page.getRecords());

        return PageDTO.of(page, permissionDTOList);
    }

    @Override
    @Transactional(rollbackFor = BizException.class)
    public IPage<TSysPermissionModule> getPermissionModuleList(ModuleQueryDTO dto) {
        IPage<TSysPermissionModule> page = new Page<>(dto.getPageNo(), dto.getPageSize());
        QueryWrapper<TSysPermissionModule> queryWrapper = new QueryWrapper<>();

        if (StrUtils.isNotBlank(dto.getName())) {
            queryWrapper.like("NAME", dto.getName());
        }
        queryWrapper.eq("STATUS", 1);

        return this.sysPermissionModuleService.getBaseMapper().selectPage(page, queryWrapper);
    }


    @Transactional(rollbackFor = BizException.class)
    public TSysRole getRoleByRoleId(Integer roleId) {
        /**
         *     select r from Role r where r.id = :roleId and r.status = 1
         */
        QueryWrapper<TSysRole> queryWrapper = new QueryWrapper<>();
        queryWrapper.in("ID", roleId);
        queryWrapper.eq("STATUS", 1);
        return this.sysRoleService.getBaseMapper().selectOne(queryWrapper);
    }


    @Transactional(rollbackFor = BizException.class)
    public Integer deleteRolePermissionByPermissionId(List<Integer> permissionIds) {
        QueryWrapper<TSysRolePermission> queryWrapper = new QueryWrapper<>();
        queryWrapper.in("PERMISSION_ID", permissionIds);
        queryWrapper.eq("STATUS", 1);
        List<TSysRolePermission> deleteList = this.sysRolePermissionService.getBaseMapper().selectList(queryWrapper);
        List<Integer> idList = deleteList.stream().map(TSysRolePermission::getId).collect(Collectors.toList());
        return this.sysRolePermissionService.getBaseMapper().deleteBatchIds(idList);
    }


    @Transactional(rollbackFor = BizException.class)
    public List<TSysRole> getRoleByName(String name) {
        /**
         *     @Query(value = "select r from Role r where r.name = :name and r.status = 1")
         *     List<Role> getRoleByName(@Param("name") String name);
         */
        QueryWrapper<TSysRole> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("NAME", name);
        queryWrapper.eq("STATUS", 1);
        return this.sysRoleService.getBaseMapper().selectList(queryWrapper);
    }


    @Transactional(rollbackFor = BizException.class)
    public TSysPermission getPermissionByPermissionId(Integer permissionId) {
        /**
         * select p from Permission p where p.id = :permissionId and p.status = 1 order by p.moduleId
         */
        QueryWrapper<TSysPermission> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("ID", permissionId);
        queryWrapper.eq("STATUS", 1);
        return this.baseMapper.selectOne(queryWrapper);
    }

    @Override
    @Transactional(rollbackFor = BizException.class)
    public TSysPermission getPermissionByCode(String code) {
        /**
         *     select p from Permission p where p.code = :code and p.status = 1 order by p.moduleId
         */
        QueryWrapper<TSysPermission> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("CODE", code);
        queryWrapper.eq("STATUS", 1);
        return this.baseMapper.selectOne(queryWrapper);
    }


    @Transactional(rollbackFor = BizException.class)
    public List<TSysPermissionModule> getPermissionModuleByName(String name) {
        /**
         *    select pm from PermissionModule pm where pm.name = :name and pm.status = 1
         */
        QueryWrapper<TSysPermissionModule> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("NAME", name);
        queryWrapper.eq("STATUS", 1);
        return this.sysPermissionModuleService.getBaseMapper().selectList(queryWrapper);
    }


    @Transactional(rollbackFor = BizException.class)
    public List<TSysPermission> getPermissionByModuleId(Integer moduleId) {
        /**
         * select p from Permission p where p.moduleId = :moduleId and p.status = 1 order by p.moduleId
         */
        QueryWrapper<TSysPermission> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("MODULE_ID", moduleId);
        queryWrapper.eq("STATUS", 1);
        return this.baseMapper.selectList(queryWrapper);
    }


    @Transactional(rollbackFor = BizException.class)
    public TSysPermissionModule getPermissionModuleById(Integer mid) {
        QueryWrapper<TSysPermissionModule> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("ID", mid);
        queryWrapper.eq("STATUS", 1);
        return this.sysPermissionModuleService.getBaseMapper().selectOne(queryWrapper);
    }


    @Transactional(rollbackFor = BizException.class)
    public List<TSysRolePermission> getRolePermissionByRoleId(Integer roleId) {
        /**
         * select rp from RolePermission rp where rp.roleId = :roleId and rp.status = 1
         */
        QueryWrapper<TSysRolePermission> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("ROLE_ID", roleId);
        queryWrapper.eq("STATUS", 1);
        return this.sysRolePermissionService.getBaseMapper().selectList(queryWrapper);
    }


    @Transactional(rollbackFor = BizException.class)
    public List<PermissionDTO> dtoGet(List<TSysPermission> permissionList) {
        if (permissionList.size() == 0) {
            return new ArrayList<>();
        }
        List<PermissionDTO> permissionDTOList = new ArrayList<>();
        List<Integer> moduleIds = permissionList.stream().map(TSysPermission::getModuleId).collect(Collectors.toList());
        QueryWrapper<TSysPermissionModule> moduleQueryWrapper = new QueryWrapper<>();
        moduleQueryWrapper.in("ID", moduleIds);
        moduleQueryWrapper.eq("STATUS", 1);
        List<TSysPermissionModule> permissionModuleList = this.sysPermissionModuleService.getBaseMapper().selectList(moduleQueryWrapper);
        Map<Integer, TSysPermissionModule> moduleMap = permissionModuleList.stream().collect(Collectors.toMap(TSysPermissionModule::getId, module -> module));
        permissionList.forEach(permission -> {
            PermissionDTO permissionDTO = new PermissionDTO();
            this.convertBean.convert(permission, permissionDTO);
            permissionDTO.setModule(moduleMap.getOrDefault(permission.getModuleId(), null));
            permissionDTOList.add(permissionDTO);
        });
        return permissionDTOList;
    }

    private List<PermissionDTO> getPermissionListByRolePermissionList(List<TSysRolePermission> rolePermissionList) {
        List<TSysPermission> permissionList = new ArrayList<>();
        if (rolePermissionList.size() > 0) {
            List<Integer> permissionIds = rolePermissionList.stream().map(TSysRolePermission::getPermissionId).collect(Collectors.toList());
            permissionList = this.getPermissionByPermissionIds(permissionIds);
        }
        return this.dtoGet(permissionList);
    }
}
